"""
JWT认证处理模块

该模块提供了JWT令牌的生成、解析、验证功能，
以及用户身份认证和凭证提取等相关功能。
"""

import uuid
from datetime import datetime, timedelta, timezone

import jwt
from fastapi.security import HTTPAuthorizationCredentials
from jwt import PyJWTError
from starlette.requests import Request

from app.core.config import settings
from app.core.handlers.database import SessionBackend


# JWT 工具函数
def create_access_token(subject: str, jti: str | None = None) -> str:
    """
    创建访问令牌(access token)

    Args:
        subject (str): 令牌的主题，通常是用户ID
        jti (str, optional): JWT ID，用于令牌黑名单检查

    Returns:
        str: 编码后的JWT访问令牌
    """
    if jti is None:
        jti = str(uuid.uuid4())

    expire = datetime.now(timezone.utc) + timedelta(
        minutes=settings.jwt_config.access_token_expire_minutes
    )
    to_encode = {
        "exp": expire,  # 过期时间
        "sub": str(subject),  # 主题(用户ID)
        "jti": jti,  # JWT唯一标识，用于黑名单
    }
    encoded_jwt = jwt.encode(
        to_encode,
        settings.jwt_config.secret_key,
        algorithm=settings.jwt_config.algorithm,
    )
    return encoded_jwt


def create_refresh_token(subject: str) -> str:
    """
    创建刷新令牌(refresh token)

    Args:
        subject (str): 令牌的主题，通常是用户ID

    Returns:
        str: 编码后的JWT刷新令牌
    """
    expire = datetime.now(timezone.utc) + timedelta(
        minutes=settings.jwt_config.refresh_token_expire_minutes
    )
    to_encode = {
        "exp": expire,  # 过期时间
        "sub": str(subject),  # 主题(用户ID)
    }
    encoded_jwt = jwt.encode(
        to_encode,
        settings.jwt_config.secret_key,
        algorithm=settings.jwt_config.algorithm,
    )
    return encoded_jwt


def decode_token(token: str) -> dict | None:
    """
    解码JWT令牌

    Args:
        token (str): JWT令牌字符串

    Returns:
        Optional[dict]: 解码后的令牌载荷，如果解码失败则返回None
    """
    try:
        payload = jwt.decode(
            token,
            settings.jwt_config.secret_key,
            algorithms=settings.jwt_config.algorithm,
        )
        return payload
    except PyJWTError:
        return None


def is_token_revoked(db: SessionBackend, jti: str) -> bool:
    """
    检查令牌是否在黑名单中

    Args:
        jti (str): JWT唯一标识

    Returns:
        bool: 如果令牌在黑名单中返回True，否则返回False
    """
    # TODO 从数据库或者Redis中检查令牌是否在黑名单中
    return False  # 实际生产环境中要实现


def add_to_blacklist(db: SessionBackend, jti: str, expire_minutes: int = 30):
    """
    将令牌添加到黑名单中

    Args:
        jti (str): JWT唯一标识
        expire_minutes (int, optional): 过期时间(分钟)
    """
    # 往数据库或者Redis中添加黑名单令牌
    pass


async def extract_credentials(
    request: Request,
) -> HTTPAuthorizationCredentials | None:
    """
    从请求中提取认证凭证

    Args:
        request (Request): HTTP请求对象

    Returns:
        Optional[HTTPAuthorizationCredentials]: 认证凭证对象，如果提取失败则返回None
    """
    authorization = request.headers.get("Authorization")
    if not authorization:
        return None

    scheme, _, param = authorization.partition(" ")
    if scheme.lower() != "bearer":
        return None

    return HTTPAuthorizationCredentials(scheme=scheme, credentials=param)
